"""
文件差异检查器

负责检查最新导出的SQL文件与Git仓库中已有文件的差异。
"""

import os
import hashlib
import logging
from typing import Dict, Any, Optional


class DiffChecker:
    """文件差异检查器
    
    负责检查最新导出的SQL文件与Git仓库中已有文件的差异。
    """
    
    def __init__(self, logger: logging.Logger = None):
        """初始化差异检查器
        
        参数:
            logger (logging.Logger): 日志记录器
        """
        self.logger = logger or logging.getLogger(__name__)
    
    def check_file_difference(self, new_file: str, existing_file: str) -> Dict[str, Any]:
        """检查文件差异
        
        比较新文件与现有文件的差异，支持文件大小和内容哈希比较。
        
        参数:
            new_file (str): 新文件路径
            existing_file (str): 现有文件路径
            
        返回:
            Dict[str, Any]: 差异检查结果
        """
        try:
            # 检查新文件是否存在
            if not os.path.exists(new_file):
                return {
                    'success': False,
                    'error': f'新文件不存在: {new_file}',
                    'has_difference': True  # 文件不存在视为有差异
                }
            
            # 检查现有文件是否存在
            if not os.path.exists(existing_file):
                return {
                    'success': True,
                    'has_difference': True,
                    'reason': '现有文件不存在',
                    'new_file_size': os.path.getsize(new_file),
                    'existing_file_size': 0
                }
            
            # 比较文件大小
            new_size = os.path.getsize(new_file)
            existing_size = os.path.getsize(existing_file)
            
            if new_size != existing_size:
                return {
                    'success': True,
                    'has_difference': True,
                    'reason': '文件大小不同',
                    'new_file_size': new_size,
                    'existing_file_size': existing_size,
                    'size_difference': abs(new_size - existing_size)
                }
            
            # 文件大小相同，比较内容哈希
            new_hash = self._calculate_file_hash(new_file)
            existing_hash = self._calculate_file_hash(existing_file)
            
            if new_hash != existing_hash:
                return {
                    'success': True,
                    'has_difference': True,
                    'reason': '文件内容不同',
                    'new_file_hash': new_hash,
                    'existing_file_hash': existing_hash,
                    'new_file_size': new_size,
                    'existing_file_size': existing_size
                }
            else:
                return {
                    'success': True,
                    'has_difference': False,
                    'reason': '文件内容相同',
                    'new_file_hash': new_hash,
                    'existing_file_hash': existing_hash,
                    'new_file_size': new_size,
                    'existing_file_size': existing_size
                }
                
        except Exception as e:
            self.logger.error(f"检查文件差异失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'has_difference': True  # 出错时视为有差异，确保安全
            }
    
    def _calculate_file_hash(self, file_path: str, algorithm: str = 'md5') -> str:
        """计算文件哈希值
        
        参数:
            file_path (str): 文件路径
            algorithm (str): 哈希算法，默认为'md5'
            
        返回:
            str: 文件哈希值
        """
        try:
            hash_func = hashlib.new(algorithm)
            
            with open(file_path, 'rb') as f:
                # 读取文件内容并计算哈希
                for chunk in iter(lambda: f.read(4096), b""):
                    hash_func.update(chunk)
            
            return hash_func.hexdigest()
            
        except Exception as e:
            self.logger.error(f"计算文件哈希失败: {e}")
            return ""
    
    def compare_backup_files(self, backup_files: list, git_backup_dir: str) -> Dict[str, Any]:
        """比较备份文件列表
        
        比较多个备份文件与Git仓库中对应文件的差异。
        
        参数:
            backup_files (list): 备份文件路径列表
            git_backup_dir (str): Git备份目录
            
        返回:
            Dict[str, Any]: 比较结果
        """
        try:
            results = []
            has_differences = False
            
            for backup_file in backup_files:
                if not os.path.exists(backup_file):
                    self.logger.warning(f"备份文件不存在: {backup_file}")
                    continue
                
                # 获取文件名
                filename = os.path.basename(backup_file)
                git_file_path = os.path.join(git_backup_dir, filename)
                
                # 检查差异
                diff_result = self.check_file_difference(backup_file, git_file_path)
                
                if diff_result.get('success', False):
                    diff_result['filename'] = filename
                    results.append(diff_result)
                    
                    if diff_result.get('has_difference', False):
                        has_differences = True
                else:
                    self.logger.error(f"检查文件差异失败: {filename}")
            
            return {
                'success': True,
                'has_differences': has_differences,
                'file_count': len(results),
                'files_with_differences': sum(1 for r in results if r.get('has_difference', False)),
                'results': results
            }
            
        except Exception as e:
            self.logger.error(f"比较备份文件失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def get_file_info(self, file_path: str) -> Dict[str, Any]:
        """获取文件信息
        
        参数:
            file_path (str): 文件路径
            
        返回:
            Dict[str, Any]: 文件信息
        """
        try:
            if not os.path.exists(file_path):
                return {
                    'success': False,
                    'error': '文件不存在',
                    'file_path': file_path
                }
            
            stat_info = os.stat(file_path)
            
            return {
                'success': True,
                'file_path': file_path,
                'file_size': stat_info.st_size,
                'modified_time': stat_info.st_mtime,
                'hash_md5': self._calculate_file_hash(file_path, 'md5'),
                'hash_sha256': self._calculate_file_hash(file_path, 'sha256')
            }
            
        except Exception as e:
            self.logger.error(f"获取文件信息失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }